package main

import (
	"bytes"
	"strconv"
	"errors"
	"strings"
	//"fmt"
)

type LFDataMakeJsonType int

const (
	LFDataMakeJsonType_Normal LFDataMakeJsonType = 0
	LFDataMakeJsonType_WithSharp = 1
	LFDataMakeJsonType_NoSharp = 2
)

func dec2hex(n byte) byte{
	if n < 10 {
		return '0' + n
	} else {
		return 'A' + n - 10
	}
}

func (lfd *LFData) WriteToJson() string {
	return lfd.WriteToJsonWithFormat(LFDataMakeJsonType_Normal)
}

func (lfd *LFData) WriteToJsonWithFormat(format LFDataMakeJsonType) string {
	var buffer bytes.Buffer
	if !lfd.writeToJsonCore(format, &buffer) {
		panic("that LFData is broken")
	}
	return buffer.String()
}

func (lfd *LFData) writeToJsonCore(format LFDataMakeJsonType, buffer *bytes.Buffer) bool {
	switch lfd.dtype {
	case LFDataType_null:
		buffer.WriteString("null")
	case LFDataType_false:
		buffer.WriteString("false")
	case LFDataType_true:
		buffer.WriteString("true")
	case LFDataType_u8, LFDataType_u16, LFDataType_u32, LFDataType_u64:
		buffer.WriteString(strconv.FormatUint(lfd.val.(uint64), 10))
	case LFDataType_s8, LFDataType_s16, LFDataType_s32, LFDataType_s64:
		buffer.WriteString(strconv.FormatInt(lfd.val.(int64), 10))
	case LFDataType_f32:
		buffer.WriteString(strconv.FormatFloat(lfd.val.(float64), 'g', -1, 32))
	case LFDataType_f64:
		buffer.WriteString(strconv.FormatFloat(lfd.val.(float64), 'g', -1, 64))
	case LFDataType_string:
		buffer.WriteByte('"')
		buffer.WriteString(lfd.val.(string))
		buffer.WriteByte('"')
	case LFDataType_binary:
		buffer.WriteByte('(')
		for _,v := range lfd.val.([]byte) {
			buffer.WriteByte(dec2hex(v/16))
			buffer.WriteByte(dec2hex(v%16))
		}
		buffer.WriteByte(')')
	case LFDataType_array:
		arr := lfd.val.(*_ArrayST)
		buffer.WriteByte('[')
		for _,v := range *arr {
			if !v.writeToJsonCore(format, buffer) {
				return false
			}
			buffer.WriteByte(',')
		}
		if len(*arr)>0 {
			buffer.Truncate(buffer.Len()-1)
		} 
		buffer.WriteByte(']')
	case LFDataType_table:
		lst := lfd.val.(*_TableST)
		buffer.WriteByte('{')
		for k,v := range *lst {
			buffer.WriteByte('"')
			buffer.WriteString(k)
			buffer.WriteByte('"')
			buffer.WriteByte(':')
			if !v.writeToJsonCore(format, buffer) {
				return false
			}
			buffer.WriteByte(',')
		}
		if len(*lst)>0 {
			buffer.Truncate(buffer.Len()-1)
		} 
		buffer.WriteByte('}')
	case LFDataType_index:
		lst := lfd.val.(*_IndexST)
		buffer.WriteByte('<')
		for k,v := range *lst {
			buffer.WriteString(strconv.FormatInt(k, 10))
			buffer.WriteByte(':')
			if !v.writeToJsonCore(format, buffer) {
				return false
			}
			buffer.WriteByte(',')
		}
		if len(*lst)>0 {
			buffer.Truncate(buffer.Len()-1)
		} 
		buffer.WriteByte('>')
	default:
		return false
	}
	return true
}

func (lfd *LFData) ReadFromJson(jsonstr string) (int, error) {
	return lfd.readFromJsonCore(jsonstr, 0)
}

func (lfd *LFData) readFromJsonCore(jsonstr string, jsonstart int) (int, error){
	lfd.Clear()
	
	i := swap_blank(jsonstr, jsonstart)
	ch := jsonstr[i]
	var err error
	switch ch {
	case '"':
		i++
		var buffer bytes.Buffer
		for ; i<len(jsonstr); {
			ch = jsonstr[i]
			if ch == '"' {
				i++
				break
			} else if ch == '\\' {
				i++
				if i != len(jsonstr) {
					switch (jsonstr[i]) {
					case '"':
						buffer.WriteByte('"')
						i++
					case '\\':
						buffer.WriteByte('\\')
						i++
					case '/':
						buffer.WriteByte('/')
						i++
					case 'b':
						buffer.WriteByte('\b')
						i++
					case 'f':
						buffer.WriteByte('\f')
						i++
					case 'n':
						buffer.WriteByte('\n')
						i++
					case 'r':
						buffer.WriteByte('\r')
						i++
					case 't':
						buffer.WriteByte('\t')
						i++
					case 'u':
						i++
						if len(jsonstr)-i <= 4 {
							return i, errors.New("error unicode")
						}
						var word rune = 0
						for j:=0; j<4; j++ {
							n, r := unhex(jsonstr[i+j])
							if !r {
								return i, errors.New("invalid unicode")
							}
							word = word*16 + n
						}
						i += 4
						buffer.WriteRune(word)
					default:
						return i, errors.New("unknow escape character")
					}
				}
			} else {
				if i < len(jsonstr) {
					buffer.WriteByte(ch);
					i++
				} else {
					return i, errors.New("invalid string eof")
				}
			}
		}
		lfd.fastSetString(buffer.String())

	case '-', '+', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
		iend := i
		loop: for ; iend<len(jsonstr); iend++{
			switch jsonstr[iend] {
			case '-', '+', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'e', 'E':
			default:
				break loop
			}
		}
		numberstr := jsonstr[i:iend]
		i = iend
		r,err := strconv.ParseInt(numberstr, 10, 64)
		if err!=nil {
			r,err := strconv.ParseFloat(numberstr, 64)
			if err!=nil {
				return i, errors.New("invalid number")
			}
			lfd.fastSetFloat64(r)
		} else {
			lfd.fastSetInt64(r)
		}

	case '[':
		lfd.MakeArray()
		i++
		//
		i = swap_blank(jsonstr, i)
		if jsonstr[i] == ']' {
			i++
			break
		}
		//
		for ; ; {
			newlfd := new(LFData)
			i, err = newlfd.readFromJsonCore(jsonstr, i)
			if err != nil {
				return i, err
			}
			lfd.fastSetToArray(newlfd)
			//
			i = swap_blank(jsonstr, i)
			if jsonstr[i] == ',' {
				i++
				continue
			} else if jsonstr[i] == ']' {
				i++
				break
			} else {
				return i, errors.New("invalid array eof")
			}
		}

	case '{':
		lfd.MakeTable()
		i++
		//
		i = swap_blank(jsonstr, i)
		if jsonstr[i] == '}' {
			i++
			break
		}
		//
		for ; ; {
			i = swap_blank(jsonstr, i)
			if jsonstr[i] != '"' {
				return i, errors.New("table key must string")
			}
			keylfd := new(LFData)
			i, err = keylfd.readFromJsonCore(jsonstr, i)
			if err != nil {
				return i, err
			}
			//
			i = swap_blank(jsonstr, i)
			if jsonstr[i] != ':' {
				return i, errors.New("invalid table separator")
			}
			i++
			//
			newlfd := new(LFData)
			i, err = newlfd.readFromJsonCore(jsonstr, i)
			if err != nil {
				return i, err
			}
			//if !lfd.fastSetToTable(keylfd.JustString(), newlfd) {
			//	return i, fmt.Errorf("table key '%s' duplicate", keylfd.AsString())
			//}
			lfd.fastSetToTable(keylfd.JustString(), newlfd)
			//
			i = swap_blank(jsonstr, i)
			if jsonstr[i] == ',' {
				i++
				continue
			} else if jsonstr[i] == '}' {
				i++
				break
			} else {
				return i, errors.New("invalid table eof")
			}
		}

	case '<':
		lfd.MakeIndex()
		i++
		//
		i = swap_blank(jsonstr, i)
		if jsonstr[i] == '>' {
			i++
			break
		}
		//
		for ; ; {
			i = swap_blank(jsonstr, i)
			if !is_number_start(jsonstr[i]) {
				return i, errors.New("index key must integer")
			}
			keylfd := new(LFData)
			i, err = keylfd.readFromJsonCore(jsonstr, i)
			if err != nil {
				return i, err
			}
			//
			i = swap_blank(jsonstr, i)
			if jsonstr[i] != ':' {
				return i, errors.New("invalid table separator")
			}
			i++
			//
			newlfd := new(LFData)
			i, err = newlfd.readFromJsonCore(jsonstr, i)
			if err != nil {
				return i, err
			}
			//if !lfd.fastSetToIndex(keylfd.JustInt64(), newlfd) {
			//	return i, fmt.Errorf("index key '%s' duplicate", keylfd.AsString())
			//}
			lfd.fastSetToIndex(keylfd.JustInt64(), newlfd)
			//
			i = swap_blank(jsonstr, i)
			if jsonstr[i] == ',' {
				i++
				continue
			} else if jsonstr[i] == '>' {
				i++
				break
			} else {
				return i, errors.New("invalid table eof")
			}
		}

	case '(':
		i++
		var buffer bytes.Buffer
		for ; i<len(jsonstr); {
			ch = jsonstr[i]
			if ch == ')' {
				i++
				break
			} else {
				if len(jsonstr) - i <= 2 {
					return i, errors.New("error binary data")
				}
				h, r := unhex(jsonstr[i])
				if !r {
					return i, errors.New("invalid binary data")
				}
				i++
				l, r := unhex(jsonstr[i])
				if !r {
					return i, errors.New("invalid binary data")
				}
				i++
				buffer.WriteByte(byte(h*16+l))
			}
		}
		lfd.fastSetBinary(buffer.Bytes())

	case 'n':
		if !strings.HasPrefix(jsonstr[i:], "null") {
			return i, errors.New("unknow label")
		}
		//lfd.Clear()
		i += 4

	case 't':
		if !strings.HasPrefix(jsonstr[i:], "true") {
			return i, errors.New("unknow label")
		}
		lfd.fastSetBool(true)
		i += 4

	case 'f':
		if !strings.HasPrefix(jsonstr[i:], "false") {
			return i, errors.New("unknow label")
		}
		lfd.fastSetBool(false)
		i += 5
		
	default:
		return i, errors.New("unknow label")
	}
	return i, nil
}

func swap_blank(jsonstr string, jsonstart int) int{
	for ; jsonstart<len(jsonstr); jsonstart++ {
		if jsonstr[jsonstart] != ' ' &&
		   jsonstr[jsonstart] != '\n' &&
		   jsonstr[jsonstart] != '\t' &&
		   jsonstr[jsonstart] != '\r' {
			   break
		   }
	}
	return jsonstart
}

func is_number_start(n byte) bool {
	switch n {
	case '-', '+', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
		return true
	}
	return false
}

func unhex(b byte) (v rune, ok bool) {
	c := rune(b)
	switch {
	case '0' <= c && c <= '9':
		return c - '0', true
	case 'a' <= c && c <= 'f':
		return c - 'a' + 10, true
	case 'A' <= c && c <= 'F':
		return c - 'A' + 10, true
	}
	return -1, false
}
